/*
** AudioBuffer.cpp - audio buffer helper class.
**
** This is used exclusively by the mixer to help do different things, such as resampling and applying different
** kinds of effects.
**
** 12/14/2009 redoing this
*/

#include "smse2kincludes.h"
#include <string.h>
#include "debug.h"

CAudioBuffer::CAudioBuffer (int sr_native, int sr_output) {
	Msg("Creating audio buffer (dev sr %d, output sr %d)\n",sr_native,sr_output);
	this->sr_native = sr_native;
	this->sr_output = sr_output;

	buf_l = new short[BUFFER_MAX_SAMPLES];
	buf_r = new short[BUFFER_MAX_SAMPLES];
	tempbuf = new short[BUFFER_MAX_SAMPLES];
	curptr_l = buf_l;
	curptr_r = buf_r;
	bufsize = BUFFER_MAX_SAMPLES;

	//Msg("AUDIO BUFFER STARTUP OK\n");
}

CAudioBuffer::~CAudioBuffer() {

}

// Reset: Called by the mixer before the frame executed.
void CAudioBuffer::Reset() {
	memset(buf_l, 0, sizeof(short) * bufsize);
	memset(buf_r, 0, sizeof(short) * bufsize);
	curptr_l = buf_l;
	curptr_r = buf_r;
	timestamp = 0;
	realtime = 0.0;
}

// DoneSamples: Called whenever the mixer has done a certain number of samples for a device.
void CAudioBuffer::DoneSamples(int count) {
	curptr_l += count;
	curptr_r += count;
	timestamp += count;

	// Add to the real time we've done
	realtime += ((double)count / (double)sr_native);
}

/*
** Resample algorithm stolen from SCC.cpp
**
** TODO: Get a better one. This works for the most part but sounds like shit, and crashes on some tracks:
**
** buf 00312F70: resampling from 466 samp to 367 samp <-- YM2151 (has enough samples)
** buf 0031DD00: resampling from 232 samp to 365 samp <-- K007232 (not enough samples? crashes)
**
** The samples that are done are not an equal amount. We might need to rip this out and use a better algorithm,
** or just add stuff later. Blerp.
*/
void CAudioBuffer::Resample() {
	
	// return, since we're sucking
	return;

	// do we need to resample?
	if (this->sr_native == this->sr_output) return;

	// algorithm modified from scc.cpp
	UINT32 realstep = ((1 << 31) / this->sr_output);
	UINT32 nativestep = ((1 << 31) / this->sr_native);
	int	   nativetime = 0;
	int	   i = 0, z = 0;
	short  oursample = 0;

	// Compute how many samples we really ran for
	Msg("buf %p: resampling from %d samp to %d samp\n",this,timestamp,(int)(realtime * sr_output));
	timestamp = (int)(realtime * sr_output) / 2;
	

	// Initialize a temp buffer
	short* temp = new short[0xffff];

	for (int x = 0; x < this->timestamp; x++) {
		while (realstep > nativetime) {
				nativetime += nativestep;
				// Get the sample and put it on the temp output
				oursample = this->buf_l[i++];
				
		}
		nativetime -= realstep;
		tempbuf[z++] = oursample;
	//	Msg("RESAMPLER wrote %d\n",z);
	}	

	memcpy(buf_l, tempbuf, timestamp);
	memset(buf_l, 0, sizeof(tempbuf));
	// Reset and do the right speaker

	oursample = z = i = nativetime = 0;


	for (int x = 0; x < this->timestamp; x++) {
		while (realstep > nativetime) {
				nativetime += nativestep;
				// Get the sample and put it on the temp output
				oursample = this->buf_r[i++];
		}
		nativetime -= realstep;
		tempbuf[z++] = oursample;
	//	Msg("RESAMPLER wrote %d\n",z);
	}	

	memcpy(buf_r, tempbuf, timestamp);
	memset(buf_r, 0, sizeof(tempbuf));

	delete[] temp;
	temp = NULL;
}

void CAudioBuffer::ApplyVolumeMix() {

	for (int i=0;i<bufsize;i++) {
			*(buf_l + i) = (double)(*(buf_l + i) * (left_volume / 0xff));
			*(buf_r + i) = (double)(*(buf_r + i) * (right_volume / 0xff));
			
	}

}

void CAudioBuffer::ResetSamplePointers() {
	curptr_l = buf_l;
	curptr_r = buf_r;
}

short* CAudioBuffer::GetLeftStream() {
	return curptr_l;
}

short* CAudioBuffer::GetRightStream() {
	return curptr_r;
}